//David Wasser
//February 20, 2009
//Software Design, Period 6
//Ultimate Frisbee

/* OffStackRoutine is the MovementRoutine that controls players
 * in an offensive stack (OffStack) strategy in which the players
 * line up in the middle of the field and cut towards or away
 * from the thrower with the disc to try to get open.
 */

import java.util.Random;
import javax.vecmath.Point3d;
import javax.vecmath.Tuple3d;
import javax.vecmath.Vector3d;
public class OffStackRoutine extends PlayerRoutine{
	private int status;
	private int nextStatus;
	private int orderPos;
	private boolean turn;
	private boolean stand;
	private Vector3d test;
	private Vector3d test2;
	private final int STAND = 0;
	private final int STACK = 1;
	private final int CUT = 2;
	private final int CLEAR = 3;
	private final int CLEAR2 = 4;
	private final int MOVE = 5;
	private final int JUMP = 6;
	Random r = new Random();
	
	/** Creates a new OffStackRoutine for the input Player at the position
	 ** under the given OffStack.
	 **/
	public OffStackRoutine(Player setPlayer, Point3d position, OffStack strat){
		this.strat = strat;
		player = setPlayer;
		player.setMovementRoutine(this);
		point = position;
		vec = new Vector3d((player.team.endZone == Team.RIGHT?1:-1),0,0);
		goal = (Point3d)point.clone();
		dir = new Vector3d();
		test2 = new Vector3d();
		test = new Vector3d();
	}//End OffStackRoutine()
	
	/** Step calculates the next point that the person is moving to, and
	 ** the player's velocity vector.
	 **/
	public Tuple3d[] step(){
		if(strat.starting)
			status = STAND;
		if(!airborn){
			switch(status){
				case STAND:
					if(turn)
						status = CUT;
					turn = false;
					stand = true;
					break;
				case STACK:
					break;
				case CUT:
					if(r.nextInt(2)==0)
						if(player.team.getOtherTeam().getDefStrategy().force == field.HOME)
							dir.sub(field.bounds, player.getPosition());
						else
							dir.sub(new Point3d(field.bounds.x, 0, 0), player.getPosition());
					else
						if(player.team.getOtherTeam().getDefStrategy().force == field.HOME)
							dir.sub(new Point3d(0, field.bounds.y, 0), player.getPosition());
						else
							dir.sub(new Point3d(field.bounds.x, 0, 0), player.getPosition());
					vec = (Vector3d)dir.clone();
					if(dir.length() < field.bounds.x/4){
						vec.scale(.8);
						goal = (Point3d)vec.clone();
						goal.add(point);
					}//End if
					vec.scale(player.speed/vec.length());
					status = MOVE;
					nextStatus = CLEAR;
					break;
				case CLEAR:
					if(player.team.strat.force == field.HOME)
						goal = new Point3d(player.position.x, player.position.y+5, 0);
					else
						goal = new Point3d(player.position.x, player.position.y-5, 0);
					vec.sub(goal, player.position);
					vec.scale(player.speed/vec.length());
					nextStatus = CLEAR2;
					break;
				case CLEAR2:
					goal = new Point3d(player.position.x, player.position.y, 0);
					nextStatus = STAND;
					break;
				case MOVE:
					dir.sub(goal, player.position);
					vec = (Vector3d)dir.clone();
					vec.scale(player.speed/vec.length());
					test2.add(vec, point);
					test.sub(point, goal);
					if(test.length()<1)
						status = nextStatus;
					break;
				case JUMP:
					vec.add(new Vector3d(0, 0, player.jumpSpeed));
					status = nextStatus;
					break;
			}//End switch
		}//End if
		vec.scale(field.dt);
		if(vec.z!=0 && point.z-vec.z<=0){
			vec.z = 0;
			point.z = 0;
		}//End if
		if(!stand)
			point.add(vec);
		stand = false;
		return new Tuple3d[] {point, vec};
	}//End move()
	
	/** Tells the OffStackRoutine where to move the Player into
	 ** the stack.
	 **/
	public void setStackPos(Point3d pos){
		if(!catching){
			goal = pos;
			status = MOVE;
			nextStatus = STAND;
		}//End if
	}//End setOrderPos()
	
	/** Is used by the OffStack to tell the routine when to cut.
	 **/
	public void setTurn(){
		turn = true;
	}//End setTurn()
}//End OffStackRoutine